from fastapi import Body, Request
from sse_starlette.sse import EventSourceResponse
from fastapi.concurrency import run_in_threadpool
from configs import (LLM_MODELS, 
                     VECTOR_SEARCH_TOP_K, 
                     SCORE_THRESHOLD, 
                     TEMPERATURE,
                     USE_RERANKER,
                     RERANKER_MODEL,
                     RERANKER_MAX_LENGTH,
                     MODEL_PATH)
from server.utils import wrap_done, get_ChatOpenAI
from server.utils import BaseResponse, get_prompt_template
from langchain.chains import LLMChain
from langchain.callbacks import AsyncIteratorCallbackHandler
from typing import AsyncIterable, List, Optional
import asyncio
from langchain.prompts.chat import ChatPromptTemplate
from server.chat.utils import History
from server.knowledge_base.kb_service.base import KBServiceFactory
import json
from urllib.parse import urlencode
from server.knowledge_base.kb_doc_api import search_docs
from server.reranker.reranker import LangchainReranker
from server.utils import embedding_device
async def text2sql_chat(query: str = Body(..., description="用户输入", examples=["你好"]),
                              knowledge_base_name: str = Body(..., description="知识库名称", examples=["samples"]),
                              top_k: int = Body(VECTOR_SEARCH_TOP_K, description="匹配向量数"),
                              score_threshold: float = Body(
                                  SCORE_THRESHOLD,
                                  description="知识库匹配相关度阈值，取值范围在0-1之间，SCORE越小，相关度越高，取到1相当于不筛选，建议设置在0.5左右",
                                  ge=0,
                                  le=2
                              ),
                              history: List[History] = Body(
                                  [],
                                  description="历史对话",
                                  examples=[[
                                      {"role": "user",
                                       "content": "我们来玩成语接龙，我先来，生龙活虎"},
                                      {"role": "assistant",
                                       "content": "虎头虎脑"}]]
                              ),
                              stream: bool = Body(False, description="流式输出"),
                              model_name: str = Body(LLM_MODELS[0], description="LLM 模型名称。"),
                              temperature: float = Body(TEMPERATURE, description="LLM 采样温度", ge=0.0, le=1.0),
                              max_tokens: Optional[int] = Body(
                                  None,
                                  description="限制LLM生成Token数量，默认None代表模型最大值"
                              ),
                              prompt_name: str = Body(
                                  "default",
                                  description="使用的prompt模板名称(在configs/prompt_config.py中配置)"
                              ),
                              request: Request = None,
                              ):
    kb = KBServiceFactory.get_service_by_name(knowledge_base_name)
    if kb is None:
        return BaseResponse(code=404, msg=f"未找到知识库 {knowledge_base_name}")

    history = [History.from_data(h) for h in history]

    async def knowledge_base_chat_iterator(
            query: str,
            top_k: int,
            history: Optional[List[History]],
            model_name: str = model_name,
            prompt_name: str = prompt_name,
    ) -> AsyncIterable[str]:
        nonlocal max_tokens
        callback = AsyncIteratorCallbackHandler()
        if isinstance(max_tokens, int) and max_tokens <= 0:
            max_tokens = None

        model = get_ChatOpenAI(
            model_name=model_name,
            temperature=temperature,
            max_tokens=max_tokens,
            callbacks=[callback],
        )

        prompt_template = get_prompt_template("text2sql_chat", "default")
        input_msg = History(role="user", content=prompt_template).to_msg_template(False)
        print('===========================input_msg==================================')
        print(input_msg)
        print('============================input_msg=================================')
        chat_prompt = ChatPromptTemplate.from_messages(
            [i.to_msg_template() for i in history] + [input_msg])

        # chain = LLMChain(prompt=chat_prompt, llm=model)
        from langchain_experimental.sql import SQLDatabaseSequentialChain
        from langchain_community.utilities.sql_database import SQLDatabase
        db = SQLDatabase.from_uri('mysql://root:GXJKbb001@localhost:3306/prisma')
        chain = SQLDatabaseSequentialChain.from_llm(model, db, query_prompt=chat_prompt, verbose=True, use_query_checker=True, return_intermediate_steps=True, top_k=3)
        # 在后台开启一个任务
        task = asyncio.create_task(wrap_done(
            chain.acall({"table_info": """
CREATE TABLE `group` (
    id INTEGER NOT NULL COMMENT '班级id' AUTO_INCREMENT,
    name VARCHAR(100) COMMENT '班级名称',
    grade_id INTEGER COMMENT '年级ID：关联grade的id',
    PRIMARY KEY (id),
    CONSTRAINT group_ibfk_1 FOREIGN KEY(grade_id) REFERENCES grade (id)
)COLLATE utf8mb4_0900_ai_ci COMMENT='班级信息表' DEFAULT CHARSET=utf8mb4 ENGINE=InnoDB


CREATE TABLE grade (
    id INTEGER NOT NULL COMMENT '年级id' AUTO_INCREMENT,
    name VARCHAR(100) COMMENT '年级名称',
    s_id INTEGER COMMENT '学校ID：关联school的id',
    PRIMARY KEY (id),
    CONSTRAINT grade_ibfk_1 FOREIGN KEY(s_id) REFERENCES school (id)
)COLLATE utf8mb4_0900_ai_ci COMMENT='年级信息表' DEFAULT CHARSET=utf8mb4 ENGINE=InnoDB

CREATE TABLE school (
    id INTEGER NOT NULL COMMENT '学校id' AUTO_INCREMENT,
    name VARCHAR(100) COMMENT '学校名称',
    PRIMARY KEY (id)
)COLLATE utf8mb4_0900_ai_ci COMMENT='学校信息表' DEFAULT CHARSET=utf8mb4 ENGINE=InnoDB

CREATE TABLE student (
    id INTEGER NOT NULL COMMENT '学生id' AUTO_INCREMENT,
    name VARCHAR(100) COMMENT '学生名称',
    age INTEGER COMMENT '年龄',
    sex CHAR(1) COMMENT '性别',
    t_id INTEGER COMMENT '老师ID：关联teacher的id',
    PRIMARY KEY (id),
    CONSTRAINT student_ibfk_1 FOREIGN KEY(t_id) REFERENCES teacher (id)
)COLLATE utf8mb4_0900_ai_ci COMMENT='学生信息表' DEFAULT CHARSET=utf8mb4 ENGINE=InnoDB

CREATE TABLE subject (
    id INTEGER NOT NULL COMMENT '科目id' AUTO_INCREMENT,
    name VARCHAR(100) COMMENT '科目名称',
    PRIMARY KEY (id)
)COLLATE utf8mb4_0900_ai_ci COMMENT='科目信息表' DEFAULT CHARSET=utf8mb4 ENGINE=InnoDB

CREATE TABLE subject_score (
    id INTEGER NOT NULL COMMENT '科目分数id' AUTO_INCREMENT,
    score INTEGER COMMENT '科目分数',
    sub_id INTEGER COMMENT '科目ID：关联subject表的id',
    stu_id INTEGER COMMENT '学生ID：关联student表的id',
    PRIMARY KEY (id),
    CONSTRAINT subject_score_ibfk_1 FOREIGN KEY(sub_id) REFERENCES subject (id),
    CONSTRAINT subject_score_ibfk_2 FOREIGN KEY(stu_id) REFERENCES student (id)
)COLLATE utf8mb4_0900_ai_ci COMMENT='科目分数表' DEFAULT CHARSET=utf8mb4 ENGINE=InnoDB

CREATE TABLE teacher (
    id INTEGER NOT NULL COMMENT '老师ID' AUTO_INCREMENT,
    name VARCHAR(100) COMMENT '老师名称',
    age INTEGER COMMENT '年龄',
    sex CHAR(1) COMMENT '性别',
    group_id INTEGER COMMENT '班级ID：关联group的id',
    sub_id INTEGER COMMENT '科目id：关联subject表中的id',
    PRIMARY KEY (id),
    CONSTRAINT teacher_ibfk_1 FOREIGN KEY(group_id) REFERENCES `group` (id),
    CONSTRAINT teacher_ibfk_2 FOREIGN KEY(sub_id) REFERENCES subject (id)
)COLLATE utf8mb4_0900_ai_ci COMMENT='老师信息表' DEFAULT CHARSET=utf8mb4 ENGINE=InnoDB
""", "question": query, "top_k": top_k}),
            callback.done),
        )

        # source_documents = []
        
        # if stream:
        #     async for token in callback.aiter():
        #         # Use server-sent-events to stream the response
        #         yield json.dumps({"answer": token}, ensure_ascii=False)
        #     yield json.dumps({"docs": source_documents}, ensure_ascii=False)
        # else:
        #     answer = ""
        #     async for token in callback.aiter():
        #         answer += token
        #     yield json.dumps({"answer": answer,
        #                       "docs": source_documents},
        #                      ensure_ascii=False)
        await task

    return EventSourceResponse(knowledge_base_chat_iterator(query, top_k, history,model_name,prompt_name))

